package com.ldj.base;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * All rights Reserved, Designed By 翼虎能源
 * Copyright:    Copyright(C) 2015-2015
 * Company       北京翼虎能源科技有限公司
 *
 * @author 吕东杰
 * @version 1.0
 * @date 2016/5/26 16:02
 * @Description Demo
 */
public class ReflectionUtils {
    private static final Log logger = LogFactory.getLog(ReflectionUtils.class);

    public ReflectionUtils() {
    }

    public static Class getSuperClassGenricType(Class clazz, int index) {
        Type genType = clazz.getGenericSuperclass();
        if(!(genType instanceof ParameterizedType)) {
            logger.warn(clazz.getSimpleName() + "\'s superclass not ParameterizedType");
            return Object.class;
        } else {
            Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
            if(index < params.length && index >= 0) {
                if(!(params[index] instanceof Class)) {
                    logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
                    return Object.class;
                } else {
                    return (Class)params[index];
                }
            } else {
                logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "\'s Parameterized Type: " + params.length);
                return Object.class;
            }
        }
    }

    public static <T> Class<T> getSuperGenericType(Class clazz) {
        return getSuperClassGenricType(clazz, 0);
    }

    public static Method getDeclaredMethod(Object object, String methodName, Class... parameterTypes) {
        Method method = null;
        Class clazz = object.getClass();

        while(clazz != Object.class) {
            try {
                method = clazz.getDeclaredMethod(methodName, parameterTypes);
                return method;
            } catch (Exception var6) {
                clazz = clazz.getSuperclass();
            }
        }

        return null;
    }

    public static Object invokeMethod(Object object, String methodName, Class<?>[] parameterTypes, Object[] parameters) {
        Method method = getDeclaredMethod(object, methodName, parameterTypes);
        method.setAccessible(true);

        try {
            if(null != method) {
                return method.invoke(object, parameters);
            }
        } catch (IllegalArgumentException var6) {
            logger.error("invokeMethod  IllegalArgumentException", var6);
        } catch (IllegalAccessException var7) {
            logger.error("invokeMethod  IllegalAccessException", var7);
        } catch (InvocationTargetException var8) {
            logger.error("invokeMethod  InvocationTargetException", var8);
        }

        return null;
    }

    public static Field getDeclaredField(Object object, String fieldName) {
        Field field = null;
        Class clazz = object.getClass();

        while(clazz != Object.class) {
            try {
                field = clazz.getDeclaredField(fieldName);
                return field;
            } catch (Exception var5) {
                clazz = clazz.getSuperclass();
            }
        }

        return null;
    }

    public static void setFieldValue(Object object, String fieldName, Object value) {
        Field field = getDeclaredField(object, fieldName);
        field.setAccessible(true);

        try {
            field.set(object, value);
        } catch (IllegalArgumentException var5) {
            logger.error("setFieldValue  IllegalArgumentException", var5);
        } catch (IllegalAccessException var6) {
            logger.error("setFieldValue  IllegalAccessException", var6);
        }

    }

    public static Object getFieldValue(Object object, String fieldName) {
        Field field = getDeclaredField(object, fieldName);
        field.setAccessible(true);

        try {
            return field.get(object);
        } catch (Exception var4) {
            logger.error("getFieldValue  IllegalAccessException", var4);
            return null;
        }
    }

    public static void copyProperties(Object source, Object target, String[] ignoreProperties) throws Exception {
        Class targetClass = target.getClass();
        Class sourceClass = source.getClass();
        PropertyDescriptor[] targetPds = Introspector.getBeanInfo(targetClass).getPropertyDescriptors();
        PropertyDescriptor[] sourcetPds = Introspector.getBeanInfo(sourceClass).getPropertyDescriptors();
        List ignoreList = ignoreProperties == null?null: Arrays.asList(ignoreProperties);
        HashMap sourcePropertyMap = new HashMap();

        int i;
        PropertyDescriptor targetPd;
        for(i = 0; i < sourcetPds.length; ++i) {
            targetPd = sourcetPds[i];
            sourcePropertyMap.put(targetPd.getName(), targetPd);
        }

        for(i = 0; i < targetPds.length; ++i) {
            targetPd = targetPds[i];
            if(targetPd.getWriteMethod() != null && (ignoreProperties == null || !ignoreList.contains(targetPd.getName()))) {
                PropertyDescriptor sourcePd = (PropertyDescriptor)sourcePropertyMap.get(targetPd.getName());
                if(sourcePd != null && sourcePd.getReadMethod() != null) {
                    try {
                        Method ex = sourcePd.getReadMethod();
                        if(!Modifier.isPublic(ex.getDeclaringClass().getModifiers())) {
                            ex.setAccessible(true);
                        }

                        Object value = ex.invoke(source, new Object[0]);
                        Method writeMethod = targetPd.getWriteMethod();
                        if(!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                            writeMethod.setAccessible(true);
                        }

                        writeMethod.invoke(target, new Object[]{value});
                    } catch (Throwable var15) {
                        throw new IllegalArgumentException("Could not copy properties from source to target", var15);
                    }
                }
            }
        }

    }
}

